import { CookieStorageStore } from './../store/cookie-storage.service';
import { SessionStorageStore } from './../store/session-storage.service';
import { AuthConfig } from './../../util/config/auth/auth.type';
import { ConfigService } from "@/package/util/config/config.service";
import { IStore } from "../store/interface";
import { mergeConfig } from '../auth.config';
import { ITokenModel } from './interface';
import { LocalStorageStore } from '../store/local-storage.service';

import { AuthReferrer } from './interface';

export class TokenService {
    private _options: AuthConfig;
    private refresh$:ITokenModel | undefined | null
    private setTime: any;
    private change$ :ITokenModel | null | undefined
    private _referrer: AuthReferrer = {};
    private store: IStore;
    configSrv: ConfigService
    constructor(createStoreName?:'LocalStorage'| 'CookieStorage' | 'SessionStorage') {
        
        //创建存储方式 默认 CookieStorageStore
        if(createStoreName == 'LocalStorage'){
            this.store = new LocalStorageStore()
        }else if(createStoreName == 'CookieStorage'){
            this.store = new CookieStorageStore()
        }else if(createStoreName == 'SessionStorage'){
            this.store = new SessionStorageStore()
        }else{
            this.store = new LocalStorageStore()
        }
        
        this.configSrv = new ConfigService()
        this._options = mergeConfig(this.configSrv);

    }
    get login_url(): string | undefined {
        return this._options.login_url;
    }
    get refresh(): any {
        this.builderRefresh();
        return this.refresh$
    }
    get options(): AuthConfig {
        return this._options;
    }
    set(data: ITokenModel): boolean {
        const res = this.store.set(this._options.store_key!, data);
        this.change$ = data
        return res;
    }
    get(type?: any): any;
    get<T extends ITokenModel>(type?: new () => T): T {
        const data = this.store.get(this._options.store_key!);
        return type ? (Object.assign(new type(), data) as T) : (data as T);
    }

    clear(options: { onlyToken: boolean } = { onlyToken: false }): void {
        let data: ITokenModel | null = null;
        if (options.onlyToken === true) {
            data = this.get() as ITokenModel;
            data.token = ``;
            this.set(data);
        } else {
            this.store.remove(this._options.store_key!);
        }
        this.change$ = data
    }
    change(): any {
        return this.change$;
    }
    private builderRefresh(): void {
        const { refreshTime, refreshOffset } = this._options;
        this.cleanRefresh();
        this.setTime = setInterval(() => {
            const item = this.get() as ITokenModel;
            const expired = item.expired || item.exp || 0;
            if (expired <= 0) {
                return null;
            }
            const curTime = new Date().valueOf() + refreshOffset!;
            let v = (expired <= curTime ? item : null);
            this.refresh$ = v
        }, refreshTime);

    }
    private cleanRefresh(): void {
        clearInterval(this.setTime)
    }


}